/*
 * StaticModelEntity.cpp
 *
 *  Created on: 17 févr. 2011
 *      Author: seeme
 */

#include "StaticDrawableEntity.h"

StaticDrawableEntity::~StaticDrawableEntity() {

}

void StaticDrawableEntity::setVBOs(){
	int bufferSize = 0;
	GLfloat* coordTab = m_model->getCoordTab();
	GLfloat* normTab = m_model->getNormTab();
	GLfloat* uvTab = m_model->getUvTab();
	GLuint* indexTab = m_model->getIndexTab();

	GLuint coordSize = m_model->getCoordTabSize();
	GLuint uvSize = m_model->getUvTabSize();
	GLuint normSize = m_model->getNormTabSize();
	GLuint indexSize = m_model->getIndexTabSize();



    glGenBuffers(TABINDEXSIZE, m_tabIndex);

	glBindBuffer(GL_ARRAY_BUFFER, m_tabIndex[0]);
	glBufferData(GL_ARRAY_BUFFER, coordSize*sizeof(GLfloat), coordTab, GL_STATIC_DRAW);


	glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &bufferSize);
	if(coordSize*sizeof(GLfloat) != (unsigned int)bufferSize)
		Log::e("SDE") << "Size mismatch for GL_ARRAY_BUFFER";


	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_tabIndex[1]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexSize*sizeof(GLuint), indexTab, GL_STATIC_DRAW);

	glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &bufferSize);
	if(indexSize*sizeof(GLuint) != (unsigned int)bufferSize)
		Log::e("SDE") << "Size mismatch for GL_ELEMENT_ARRAY_BUFFER";

	glBindBuffer(GL_ARRAY_BUFFER, m_tabIndex[2]);
	glBufferData(GL_ARRAY_BUFFER, uvSize*sizeof(GLfloat), uvTab, GL_STATIC_DRAW);

	glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &bufferSize);
	if(uvSize*sizeof(GLuint) != (unsigned int)bufferSize)
		Log::e("SDE") << "Size mismatch for uvs";

	glBindBuffer(GL_ARRAY_BUFFER, m_tabIndex[3]);
	glBufferData(GL_ARRAY_BUFFER, normSize*sizeof(GLfloat), normTab, GL_STATIC_DRAW);

	glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &bufferSize);
	if(normSize*sizeof(GLuint) != (unsigned int)bufferSize)
		Log::e("SDE") << "Size mismatch for normals";

}

StaticDrawableEntity::StaticDrawableEntity(Vect4<float> translation, Vect4<float> rotation, Vect4<float> scale, Mesh* model):
			m_position(), m_model(model), m_tabIndex(){
	setVBOs();
	//On calcul la matrice associée
	//La matrice de rotation est donnée en degré->on convertis
	rotation = rotation * ((2*M_PI)/180);
	computTransfos(translation, rotation, scale);
}

Matrix4<float>& StaticDrawableEntity::getTransfos(const Matrix4<float>& model){
	m_transfos = model * m_initialTransfos;
	m_position = m_transfos.getColumn(3);
	return m_transfos;
}

void StaticDrawableEntity::draw(std::string programName){
	//Log::i("SDE") << "Drawing " << m_model->getModelName() << ", " << m_position;
	//On récupère le bon shader
	GLuint program = getProgramId(programName);

	//MAJ du matériau
	m_model->sendMaterial(program);

	//MAJ des textures
	glEnable(GL_TEXTURE_2D);
		m_model->sendTexture(program);
		glEnableClientState(GL_VERTEX_ARRAY);
			glBindBuffer(GL_ARRAY_BUFFER, m_tabIndex[2]);
			glEnableVertexAttribArray(glGetAttribLocation(program, "uv"));
			glVertexAttribPointer(glGetAttribLocation(program, "uv"), 2, GL_FLOAT, GL_FALSE, 0, 0);

			glBindBuffer(GL_ARRAY_BUFFER, m_tabIndex[3]);
			glEnableVertexAttribArray(glGetAttribLocation(program, "norm"));
			glVertexAttribPointer(glGetAttribLocation(program, "norm"), 3, GL_FLOAT, GL_FALSE, 0, 0);

			glBindBuffer(GL_ARRAY_BUFFER, m_tabIndex[0]);
			glEnableVertexAttribArray(glGetAttribLocation(program, "position"));
			glVertexAttribPointer(glGetAttribLocation(program, "position"), 3, GL_FLOAT, GL_FALSE, 0, 0);


			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_tabIndex[1]);
			glDrawElements(GL_TRIANGLES, m_model->getIndexTabSize(), GL_UNSIGNED_INT, 0);

			//On efface tout pour le prochain draw.
			glBindBuffer(GL_ARRAY_BUFFER, 0);
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
			glDisableVertexAttribArray(glGetAttribLocation(program, "position"));
			glDisableVertexAttribArray(glGetAttribLocation(program, "uv"));
			glDisableVertexAttribArray(glGetAttribLocation(program, "norm"));

		glDisableClientState(GL_VERTEX_ARRAY);
	glDisable(GL_TEXTURE_2D);
	//glUseProgram(0);

	//Test
	/*Log::i("SDE") << "START";
	for(int i = 0; i < m_model->getIndexTabSize(); ++i){
		int index = m_model->getIndexTab()[i];
		Log::i("SDE") << index << ": (" << m_model->getCoordTab()[3*index] << ", "
										<< m_model->getCoordTab()[3*index+1] << ", "
										<< m_model->getCoordTab()[3*index+2] << "), ("
										<< m_model->getUvTab()[2*index] << ", "
										<< m_model->getUvTab()[2*index+1] << "), ("
										<< m_model->getNormTab()[3*index] << ", "
										<< m_model->getNormTab()[3*index+1] << ", "
										<< m_model->getNormTab()[3*index+2] << ")";
	}
	Log::i("SDE") << "STOP";*/
}

std::string StaticDrawableEntity::getModelName(){
	return m_model->getModelName();
}

void StaticDrawableEntity::computTransfos(Vect4<float>& translation, Vect4<float>& rotation, Vect4<float>& scale){

	Matrix4<float> rot, tran, sca;

	m_transfos.setIdentity();

	//Translations
	tran.setColumn(translation, 3);

	//Rotations
	float A, B, C, D, E, F, AD, BD, angleX, angleY, angleZ;

	angleX = rotation.x * M_PI/180;
	angleY = rotation.y * M_PI/180;
	angleZ = rotation.z * M_PI/180;

	A       = cos(angleX);
	B       = sin(angleX);
	C       = cos(angleY);
	D       = sin(angleY);
	E       = cos(angleZ);
	F       = sin(angleZ);

	AD      =   A * D;
	BD      =   B * D;

	rot(0)  =   C * E;
	rot(1)  =  -C * F;
	rot(2)  =  -D;
	rot(4)  = -BD * E + A * F;
	rot(5)  =  BD * F + A * E;
	rot(6)  =  -B * C;
	rot(8)  =  AD * E + B * F;
	rot(9)  = -AD * F + B * E;
	rot(10) =   A * C;

	rot(3)  =  rot(7) = rot(11) = rot(12) = rot(13) = rot(14) = 0;
	rot(15) =  1;

	//Scalaire
	sca(0) = scale.x;
	sca(5) = scale.y;
	sca(10) = scale.z;

	m_initialTransfos = tran * rot * sca;
	m_position = m_initialTransfos * m_position;


	/*glTranslatef(m_position.x, m_position.y, m_position.z);

		glRotatef(m_rotation.x, 1, 0, 0);
		glRotatef(m_rotation.y, 0, 1, 0);
		glRotatef(m_rotation.z, 0, 0, 1);

		glScalef(m_scale.x, m_scale.y, m_scale.z);*/
}

